package com.wbk.lotterysystemlotteryservice.controller.auth.biz;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wbk.lotterysystemlotteryservice.commons.bo.DrawLotteryBO;
import com.wbk.lotterysystemlotteryservice.commons.bo.LotteryBO;
import com.wbk.lotterysystemlotteryservice.commons.dto.*;
import com.wbk.lotterysystemlotteryservice.entity.Lottery;
import com.wbk.lotterysystemlotteryservice.entity.Prize;
import com.wbk.lotterysystemlotteryservice.entity.QrCode;
import com.wbk.lotterysystemlotteryservice.entity.Record;
import com.wbk.lotterysystemlotteryservice.service.LotteryService;
import com.wbk.lotterysystemlotteryservice.service.PrizeService;
import com.wbk.lotterysystemlotteryservice.service.QrCodeService;
import com.wbk.lotterysystemlotteryservice.service.RecordService;
import com.wbk.system.feign.UploadFeign;
import com.wbk.user.feign.StoreFeign;
import com.wbk.user.feign.UserFeign;
import com.wbk.user.vo.StoreVO;
import com.wbk.user.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import result.Result;
import tools.QrUtil;
import tools.TimeUtil;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;

@Component
@Slf4j
public class LotteryBiz {

    @Value("${ip}")
    private String ip;

    @Autowired
    StoreFeign storeFeign;

    @Autowired
    UploadFeign uploadFeign;

    @Autowired
    LotteryService lotteryService;

    @Autowired
    PrizeService prizeService;

    @Autowired
    QrCodeService qrCodeService;

    @Autowired
    RecordService recordService;

    @Autowired
    UserFeign userFeign;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Transactional(propagation = Propagation.REQUIRED)
    public Result<LotteryDTO> createLottery(LotteryBO lotteryBO) {
        StoreVO store = storeFeign.storeDetail(lotteryBO.getStoreUserNo()).getData();
        if (store == null) {
            return new Result<>(100, "该用户还不是商家，无法发布抽奖活动", null);
        }
        if (store.getAuditStatus() != 1) {
            return new Result<>(100, "该用户还没有完成商家认证，不能发布抽奖活动", null);
        }

        //保存抽奖活动
        Lottery lottery = lotteryService.save(lotteryBO);

        String url = null;
        //生成二维码临时存到本地
        File file = QrUtil.QrCode("http://" + ip + "/lottery?id=" + lottery.getId(), lotteryBO.getStoreUserNo());
        try {
            //将二维码上传到COS，并获得返回的url
            url = uploadFeign.uploadQrCode(lotteryBO.getStoreUserNo(), file);
        } catch (IOException e) {
            log.error("io异常", e);
        }
        if (url == null) {
            throw new RuntimeException("上传失败");
        }
        //保存二维码
        QrCode qrCode = qrCodeService.save(lottery.getId(), url);

        //保存奖品
        List<Prize> prizes = prizeService.save(lottery.getId(), lotteryBO.getPrizeBOList());

        LotteryDTO lotteryDTO = new LotteryDTO();
        BeanUtils.copyProperties(lottery, lotteryDTO);

        List<PrizeDTO> prizeDTOList = new ArrayList<>();
        for (Prize prize : prizes) {
            PrizeDTO prizeDTO = new PrizeDTO();
            BeanUtils.copyProperties(prize, prizeDTO);
            prizeDTOList.add(prizeDTO);
        }
        lotteryDTO.setStoreName(store.getStoreName());
        lotteryDTO.setPrizeDTOList(prizeDTOList);
        lotteryDTO.setQrCode(qrCode.getQrCode());
        return new Result<>(200, "创建成功", lotteryDTO);
    }

    public Result<PageInfo> lotteryListWithoutAudit(Integer pageNum, Integer pageSize, Integer navigatePages) {
        PageHelper.startPage(pageNum, pageSize);
        List<Lottery> lotterys = lotteryService.getAllWithoutAudit();

        List<LotteryDTO> lotteryDTOS = new ArrayList<>();
        for (Lottery lottery : lotterys) {
            LotteryDTO lotteryDTO = new LotteryDTO();
            BeanUtils.copyProperties(lottery, lotteryDTO);

            List<Prize> prizes = prizeService.getPrizeByLotteryId(lottery.getId());
            List<PrizeDTO> prizeDTOList = new ArrayList<>();
            for (Prize prize : prizes) {
                PrizeDTO prizeDTO = new PrizeDTO();
                BeanUtils.copyProperties(prize, prizeDTO);
                prizeDTOList.add(prizeDTO);
            }
            lotteryDTO.setPrizeDTOList(prizeDTOList);

            QrCode qrCode = qrCodeService.getQrCodeByLotteryId(lottery.getId());
            lotteryDTO.setQrCode(qrCode.getQrCode());

            Result<StoreVO> result = storeFeign.storeDetail(lottery.getStoreUserNo());
            lotteryDTO.setStoreName(result.getData().getStoreName());

            lotteryDTOS.add(lotteryDTO);
        }

        PageInfo pageInfo = new PageInfo(lotterys, navigatePages);
        pageInfo.setList(lotteryDTOS);
        return new Result<>(200, "待审核的抽奖活动", pageInfo);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public Result<LotteryDTO> updateLottery(LotteryBO lotteryBO, Integer id) {
        Lottery lottery = lotteryService.getLotteryById(id);
        if (lottery == null) {
            return new Result<>(100, "此抽奖活动不存在", null);
        }
        if (lottery.getAuditStatus() != 2) {
            return new Result<>(100, "此抽奖活动处于待审核状态或已通过审核，不能修改", null);
        }
        if (!lottery.getStoreUserNo().equals(lotteryBO.getStoreUserNo())) {
            return new Result<>(100, "不是此抽奖活动的创建者，不能修改", null);
        }
        Result<StoreVO> result = storeFeign.storeDetail(lottery.getStoreUserNo());

        //先修改抽奖活动表
        BeanUtils.copyProperties(lotteryBO, lottery);
        lottery.setAuditStatus((byte) 0);
        lottery.setAuditOpinion("");
        lotteryService.update(lottery);

        QrCode qrcode = qrCodeService.getQrCodeByLotteryId(lottery.getId());

        //再修改奖品表
        List<Prize> prizes = prizeService.update(lottery.getId(), lotteryBO.getPrizeBOList());

        LotteryDTO lotteryDTO = new LotteryDTO();
        BeanUtils.copyProperties(lottery, lotteryDTO);

        List<PrizeDTO> prizeDTOList = new ArrayList<>();
        for (Prize prize : prizes) {
            PrizeDTO prizeDTO = new PrizeDTO();
            BeanUtils.copyProperties(prize, prizeDTO);
            prizeDTOList.add(prizeDTO);
        }

        lotteryDTO.setStoreName(result.getData().getStoreName());
        lotteryDTO.setPrizeDTOList(prizeDTOList);
        lotteryDTO.setQrCode(qrcode.getQrCode());
        return new Result<>(200, "修改成功", lotteryDTO);
    }

    public Result<PageInfo> allLottery(Integer pageNum, Integer pageSize, Integer navigatePages, Long storeUserNo) {
        PageHelper.startPage(pageNum, pageSize);
        List<Lottery> lotterys = lotteryService.getAllByStoreUserNo(storeUserNo);
        if (lotterys.isEmpty()) {
            return new Result<>(100, "该商家还没创建抽奖活动", null);
        }

        Result<StoreVO> result = storeFeign.storeDetail(storeUserNo);

        List<LotteryDTO> lotteryDTOS = new ArrayList<>();

        for (Lottery lottery : lotterys) {
            LotteryDTO lotteryDTO = new LotteryDTO();
            BeanUtils.copyProperties(lottery, lotteryDTO);
            lotteryDTO.setStoreName(result.getData().getStoreName());

            List<Prize> prizes = prizeService.getPrizeByLotteryId(lottery.getId());
            List<PrizeDTO> prizeDTOS = new ArrayList<>();
            for (Prize prize : prizes) {
                PrizeDTO prizeDTO = new PrizeDTO();
                BeanUtils.copyProperties(prize, prizeDTO);
                prizeDTOS.add(prizeDTO);
            }
            lotteryDTO.setPrizeDTOList(prizeDTOS);

            QrCode qrCode = qrCodeService.getQrCodeByLotteryId(lottery.getId());
            lotteryDTO.setQrCode(qrCode.getQrCode());

            lotteryDTOS.add(lotteryDTO);
        }

        PageInfo pageInfo = new PageInfo(lotterys, navigatePages);
        pageInfo.setList(lotteryDTOS);
        return new Result<>(200, "该商家所创建的抽奖活动", pageInfo);
    }

    public Result<List<LotteryRecordDTO>> lotteryRecord(Integer id) {
        Lottery lottery = lotteryService.getLotteryById(id);
        if (lottery == null) {
            return new Result<>(100, "此抽奖活动不存在", null);
        }
        List<LotteryRecordDTO> lotteryRecordDTOS = new ArrayList<>();

        List<Record> records = recordService.getAllWithLottery(id);

        for (Record record : records) {
            LotteryRecordDTO lotteryRecordDTO = new LotteryRecordDTO();
            lotteryRecordDTO.setLotteryTitle(lottery.getLotteryTitle());
            lotteryRecordDTO.setName(record.getName());
            if (record.getLotteryResult() == 0) {
                lotteryRecordDTO.setResult("未开奖");
            }
            if (record.getLotteryResult() == -1) {
                lotteryRecordDTO.setResult("没中奖");
            }
            if (record.getLotteryResult() == 1) {
                lotteryRecordDTO.setResult("中奖");
            }
            if (record.getPrizeId() == null) {//未开奖或没中奖
                lotteryRecordDTO.setPrizeLevel("");
                lotteryRecordDTO.setPrizeContent("");
            } else {
                Prize prize = prizeService.getPrizeById(record.getPrizeId());
                lotteryRecordDTO.setPrizeLevel(prize.getPrizeLevel());
                lotteryRecordDTO.setPrizeContent(prize.getPrizeContent());
            }
            lotteryRecordDTO.setCreateTime(record.getCreateTime());
            lotteryRecordDTO.setMobile(record.getMobile());
            lotteryRecordDTO.setEmail(record.getEmail());

            lotteryRecordDTOS.add(lotteryRecordDTO);
        }

        return new Result<>(200, "抽奖记录", lotteryRecordDTOS);
    }

    public Result<String> exportRecord(Integer id, HttpServletResponse response) {
        Lottery lottery = lotteryService.getLotteryById(id);
        if (lottery == null) {
            return new Result<>(100, "此抽奖活动不存在", null);
        }

        List<LotteryRecordDTO> lotteryRecordDTOS = new ArrayList<>();

        List<Record> records = recordService.getAllWithLottery(id);

        for (Record record : records) {
            LotteryRecordDTO lotteryRecordDTO = new LotteryRecordDTO();
            lotteryRecordDTO.setLotteryTitle(lottery.getLotteryTitle());
            lotteryRecordDTO.setName(record.getName());
            if (record.getLotteryResult() == 0) {
                lotteryRecordDTO.setResult("未开奖");
            }
            if (record.getLotteryResult() == -1) {
                lotteryRecordDTO.setResult("没中奖");
            }
            if (record.getLotteryResult() == 1) {
                lotteryRecordDTO.setResult("中奖");
            }
            if (record.getPrizeId() == null) {//未开奖或没中奖
                lotteryRecordDTO.setPrizeLevel("");
                lotteryRecordDTO.setPrizeContent("");
            } else {
                Prize prize = prizeService.getPrizeById(record.getPrizeId());
                lotteryRecordDTO.setPrizeLevel(prize.getPrizeLevel());
                lotteryRecordDTO.setPrizeContent(prize.getPrizeContent());
            }
            lotteryRecordDTO.setCreateTime(record.getCreateTime());
            lotteryRecordDTO.setMobile(record.getMobile());
            lotteryRecordDTO.setEmail(record.getEmail());

            lotteryRecordDTOS.add(lotteryRecordDTO);
        }
        List<LotteryRecordDTO> rows = CollUtil.newArrayList(lotteryRecordDTOS);
        ExcelWriter writer = ExcelUtil.getBigWriter();
        writer.addHeaderAlias("lotteryTitle", "抽奖标题");
        writer.addHeaderAlias("name", "姓名");
        writer.addHeaderAlias("result", "抽奖结果");
        writer.addHeaderAlias("prizeLevel", "奖品等级");
        writer.addHeaderAlias("prizeContent", "奖品内容");
        writer.addHeaderAlias("createTime", "参与时间");
        writer.addHeaderAlias("mobile", "手机号");
        writer.addHeaderAlias("email", "邮箱");
        //设置指定列的宽度，-1表示所有列
        writer.setColumnWidth(-1, 18);

        ServletOutputStream out = null;
        try {
            String fileName = URLEncoder.encode(lottery.getLotteryTitle(), "UTF-8");
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            out = response.getOutputStream();
            writer.write(rows, true);
            writer.flush(out);
        } catch (Exception e) {
            log.error("导出失败", e);
            return null;
        } finally {
            writer.close();
            IoUtil.close(out);
        }
        return null;
    }

    public Result<List<LotteryWinDTO>> lotteryWin(Integer id) {
        Lottery lottery = lotteryService.getLotteryById(id);
        if (lottery == null) {
            return new Result<>(100, "此抽奖活动不存在", null);
        }
        List<LotteryWinDTO> lotteryWinDTOS = new ArrayList<>();

        List<Record> records = recordService.getWinner(lottery.getId());

        for (Record record : records) {
            LotteryWinDTO lotteryWinDTO = new LotteryWinDTO();
            lotteryWinDTO.setLotteryTitle(lottery.getLotteryTitle());
            lotteryWinDTO.setName(record.getName());
            Prize prize = prizeService.getPrizeById(record.getPrizeId());
            lotteryWinDTO.setPrizeLevel(prize.getPrizeLevel());
            lotteryWinDTO.setPrizeContent(prize.getPrizeContent());
            lotteryWinDTO.setCreateTime(record.getCreateTime());
            lotteryWinDTO.setMobile(record.getMobile());
            lotteryWinDTO.setEmail(record.getEmail());

            lotteryWinDTOS.add(lotteryWinDTO);
        }

        return new Result<>(200, "中奖纪录", lotteryWinDTOS);
    }


    public Result<String> exportWin(Integer id, HttpServletResponse response) {
        Lottery lottery = lotteryService.getLotteryById(id);
        if (lottery == null) {
            return new Result<>(100, "此抽奖活动不存在", null);
        }

        List<LotteryWinDTO> lotteryWinDTOS = new ArrayList<>();

        List<Record> records = recordService.getWinner(lottery.getId());

        for (Record record : records) {
            LotteryWinDTO lotteryWinDTO = new LotteryWinDTO();
            lotteryWinDTO.setLotteryTitle(lottery.getLotteryTitle());
            lotteryWinDTO.setName(record.getName());
            Prize prize = prizeService.getPrizeById(record.getPrizeId());
            lotteryWinDTO.setPrizeLevel(prize.getPrizeLevel());
            lotteryWinDTO.setPrizeContent(prize.getPrizeContent());
            lotteryWinDTO.setCreateTime(record.getCreateTime());
            lotteryWinDTO.setMobile(record.getMobile());
            lotteryWinDTO.setEmail(record.getEmail());

            lotteryWinDTOS.add(lotteryWinDTO);
        }
        List<LotteryWinDTO> rows = CollUtil.newArrayList(lotteryWinDTOS);
        ExcelWriter writer = ExcelUtil.getBigWriter();
        writer.addHeaderAlias("lotteryTitle", "抽奖标题");
        writer.addHeaderAlias("name", "姓名");
        writer.addHeaderAlias("prizeLevel", "奖品等级");
        writer.addHeaderAlias("prizeContent", "奖品内容");
        writer.addHeaderAlias("createTime", "参与时间");
        writer.addHeaderAlias("mobile", "手机号");
        writer.addHeaderAlias("email", "邮箱");
        //设置指定列的宽度，-1表示所有列
        writer.setColumnWidth(-1, 18);

        ServletOutputStream out = null;
        try {
            String fileName = URLEncoder.encode(lottery.getLotteryTitle(), "UTF-8");
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            out = response.getOutputStream();
            writer.write(rows, true);
            writer.flush(out);
        } catch (Exception e) {
            log.error("导出失败", e);
            return null;
        } finally {
            writer.close();
            IoUtil.close(out);
        }
        return null;
    }

    public Result<PageInfo> hasJoin(Integer pageNum, Integer pageSize, Integer navigatePages, Long userNo) {
        Result<UserVO> user = userFeign.user(userNo);
        if (user.getCode() == 100) {
            return new Result<>(100, "用户不存在", null);
        }
        List<Integer> ids = new ArrayList<>();
        List<Record> records = recordService.hasJoin(userNo);
        for (Record record : records) {
            ids.add(record.getLotteryId());
        }
        if (ids.isEmpty()) {
            return new Result<>(100, "该用户还没参与过任何抽奖活动", null);
        }
        PageHelper.startPage(pageNum, pageSize);
        List<Lottery> lotterys = lotteryService.getAllHasJoin(ids);


        List<MyRecordDTO> myRecordDTOS = new ArrayList<>();

        for (Lottery lottery : lotterys) {
            MyRecordDTO myRecordDTO = new MyRecordDTO();
            BeanUtils.copyProperties(lottery, myRecordDTO);

            List<Prize> prizes = prizeService.getPrizeByLotteryId(lottery.getId());
            List<PrizeDTO> prizeDTOS = new ArrayList<>();
            for (Prize prize : prizes) {
                PrizeDTO prizeDTO = new PrizeDTO();
                BeanUtils.copyProperties(prize, prizeDTO);
                prizeDTOS.add(prizeDTO);
            }
            myRecordDTO.setPrizeDTOList(prizeDTOS);
            if (lottery.getLotteryStatus() == 0) {
                myRecordDTO.setResult("未开奖");
            } else if (lottery.getLotteryStatus() == 1) {
                myRecordDTO.setResult("已开奖");
            }

            myRecordDTOS.add(myRecordDTO);
        }

        PageInfo pageInfo = new PageInfo(lotterys, navigatePages);
        pageInfo.setList(myRecordDTOS);
        return new Result<>(200, "该用户参加过的的抽奖活动", pageInfo);
    }

    public Result<ResultDTO> isWin(Integer id, Long userNo) {
        Lottery lottery = lotteryService.getLotteryById(id);
        if (lottery == null) {
            return new Result<>(100, "此抽奖活动不存在", null);
        }
        Result<UserVO> user = userFeign.user(userNo);
        if (user.getCode() == 100) {
            return new Result<>(100, "用户不存在", null);
        }
        ResultDTO resultDTO = new ResultDTO();
        Record record = recordService.query(id, userNo);
        if (record == null) {
            return new Result<>(100, "该用户没有参加该抽奖活动", null);
        }
        if (record.getLotteryResult() == 0) {
            resultDTO.setFlag("该抽奖活动还未开奖");
            resultDTO.setPrizeLevel("");
            resultDTO.setPrizeContent("");
            return new Result<>(200, "未开奖", resultDTO);
        }
        if (record.getLotteryResult() == -1) {
            resultDTO.setFlag("您这次没有中奖，不要灰心，只要您积极参与机会还是有的！");
            resultDTO.setPrizeLevel("");
            resultDTO.setPrizeContent("");
            return new Result<>(200, "没有中奖", resultDTO);
        }
        Prize prize = prizeService.getPrizeById(record.getPrizeId());
        resultDTO.setFlag("恭喜您，中奖啦!");
        resultDTO.setPrizeLevel(prize.getPrizeLevel());
        resultDTO.setPrizeContent(prize.getPrizeContent());
        return new Result(200, "中奖", resultDTO);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public Result drawLottery(DrawLotteryBO drawLotteryBO) {
        Lottery lottery = lotteryService.getLotteryById(drawLotteryBO.getId());
        if (lottery == null) {
            return new Result(100, "此抽奖活动不存在", null);
        }
        if (!lottery.getStoreUserNo().equals(drawLotteryBO.getStoreUserNo())) {
            return new Result(100, "不是该抽奖活动的创建者，不能开奖", null);
        }
        if (lottery.getAuditStatus() != 1) {
            return new Result(100, "此抽奖活动还未通过审核", null);
        }
        if (lottery.getLotteryStatus() != 0) {
            return new Result(100, "此抽奖活动已经开过奖了，不能再重复操作", null);
        }
        //时间判断
        boolean flag = TimeUtil.isAfterDueTime(new Date(), lottery.getDueTime());
        if (!flag) {
            return new Result(100, "还没到截止时间，不能开奖", null);
        }

        Stack<Integer> stack = new Stack<>();

        List<Prize> prizes = prizeService.getPrizeByLotteryId(lottery.getId());
        //总的奖品数
        int totalPrizeNums = 0;
        for (Prize prize : prizes) {
            Integer prizeNums = prize.getPrizeNums();
            for (int i = 0; i < prizeNums; i++) {
                stack.push(prize.getId());
            }
            totalPrizeNums += prize.getPrizeNums();
        }
//        System.out.println("总的奖品数" + totalPrizeNums);
        Collections.shuffle(stack);

        //当前已参与人数
        String personNumsKey = "抽奖活动id-" + lottery.getId() + "的当前已参与人数:";
        int currentPersonNums = Integer.parseInt(stringRedisTemplate.opsForValue().get(personNumsKey));
//        System.out.println("当前已参与人数" + currentPersonNums);

        //当前参与人数不得少于最低参与人数，否则抽奖活动流盘
        if (currentPersonNums < lottery.getMinimumPerson()) {
            return new Result<>(100, "当前参与人数不足，该抽奖活动无法开奖，将按流盘处理", null);
        }

        //参与名单
        String lotteryKey = "抽奖活动-" + lottery.getId() + "的参与者:";
        List<Record> records = recordService.getAllWithLottery(lottery.getId());
        for (Record record : records) {
            stringRedisTemplate.opsForSet().add(lotteryKey, String.valueOf(record.getUserNo()));
        }
        Set<String> members = stringRedisTemplate.opsForSet().members(lotteryKey);
//        System.out.println("参与者名单" + members);

        //中奖名单
        List<String> winningLists = stringRedisTemplate.opsForSet().pop(lotteryKey, totalPrizeNums);
//        System.out.println("中奖名单" + winningLists);

        //中奖
        for (String userNo : winningLists) {
            Record record = recordService.query(lottery.getId(), Long.parseLong(userNo));
            record.setLotteryResult((byte) 1);//设置抽奖结果为中奖
            record.setPrizeId(stack.pop());//分配奖品
            recordService.update(record);//更新到数据库
        }

        //没中奖
        members.removeAll(winningLists);
        for (String userNo : members) {
            Record record = recordService.query(lottery.getId(), Long.parseLong(userNo));
            record.setLotteryResult((byte) -1);
            record.setPrizeId(null);
            recordService.update(record);//更新到数据库
        }

        //修改该抽奖活动的抽奖状态为已开奖
        lottery.setLotteryStatus((byte)1);
        lotteryService.update(lottery);

        //删除redis两个key
        stringRedisTemplate.delete(personNumsKey);
        if(stringRedisTemplate.hasKey(lotteryKey)){
            stringRedisTemplate.delete(lotteryKey);
        }

        return new Result(200,"开奖成功",null);
    }
}
